<template>
	<view style="z-index: -99;height: 1800rpx;">
		<canvas :canvas-id="canvasID" :style="{width:canvasWidth+'px',height:canvasHeight+'px'}"></canvas>
		<view v-if="qrCode == ''">
			<QRCode ref="qrcode" />
		</view>
	</view>
</template>

<script>
	import QRCode from "../qr_code/qrcode.vue"
	export default {
		name: 'canvas-images',
		props: {
			// canvasID 等同于 canvas-id
			canvasID: {
				Type: String,
				default: 'shareCanvas'
			},
			canvasWidth: { // 画布宽度
				Type: 'int',
				default: 750
			},
			canvasHeight: { // 画布高度
				Type: 'int',
				default: 750
			},
			shareTitle: { // 分享标题
				Type: 'String',
				default: '我是这张图片的标题'
			},
			goodsTitle: { // 商品宣传标题
				Type: 'String',
				default: '我是这张图片的标题我是这张图片的标题我是这张图片的标'
			},
			shareImage: { // 分享图片
				Type: 'String',
				default: 'https://baijixing.oss-cn-chengdu.aliyuncs.com/2025/APRIL/21/1745222511957_2ca4db3a-d5b5-40bd-b163-ce28aeeaacef.png'
			},
			qrSize: { // 二维码大小
				Type: 'int',
				default: 100
			},
			qrUrl: { // 生成二维码的链接
				Type: 'String',
				default: 'https://ext.dcloud.net.cn/plugin?id=5747'
			},
			avater: {
				Type: 'String',
				default: 'https://baijixing.oss-cn-chengdu.aliyuncs.com/2025/MAY/8/1746670386837_a8120aca-b532-4693-9259-97cd910b1fd4.png'
			},
			phone: {
				Type: 'String',
				default: '18166460411'
			}
		},
		components: {
			QRCode
		},
		data() {
			return {
				qrCode: '', // 二维码
			}
		},
		
		methods: {
			// #ifdef H5
			// 创建二维码
			canvasCreate() {
				this.$refs.qrcode.make({
						size: this.qrSize,
						text: this.qrUrl
					})
					.then(res => {
						// 返回的res与uni.canvasToTempFilePath返回一致
						this.qrCode = res.tempFilePath;
						this.onCanvas();
					});
			},
			// #endif
			drawCircularImage(ctx, img, x, y, radius) {
				ctx.save();
				ctx.beginPath();
				ctx.arc(x, y, radius, 0, Math.PI * 2);
				ctx.clip();
				ctx.drawImage(img, x - radius, y - radius, radius * 2, radius * 2);
				ctx.restore();
			},

			// base64转临时文件路径（微信小程序环境）
			base64ToTempFilePath(base64Str) {
				return new Promise((resolve, reject) => {
					// 去除base64前缀
					const base64 = base64Str.replace(/^data:image\/\w+;base64,/, '');
					const filePath = `${wx.env.USER_DATA_PATH}/qrcode.png`;
					const buffer = wx.base64ToArrayBuffer(base64);

					wx.getFileSystemManager().writeFile({
						filePath,
						data: buffer,
						encoding: 'binary',
						success: () => {
							resolve(filePath);
						},
						fail: err => {
							console.error('Base64转临时文件失败:', err);
							reject(err);
						}
					});
				});
			},

			// 画图
			async onCanvas() {
				// #ifdef MP-WEIXIN
				this.qrCode = this.qrUrl
				// 微信小程序环境下，qrCode是base64格式，需要转换为临时文件路径
				if (this.qrCode.startsWith('data:image')) {
					try {
						this.qrCode = await this.base64ToTempFilePath(this.qrCode);
					} catch (err) {
						console.error('二维码Base64转换失败:', err);
						uni.showToast({
							title: '二维码生成失败',
							icon: 'none'
						});
						return;
					}
				}
				// #endif
				uni.showLoading({
					title: "分享图片生成中..."
				});

				const ctx = uni.createCanvasContext(this.canvasID, this);
				// 设置 canvas 背景色
				ctx.setFillStyle('#FFFFFF');
				ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
				ctx.setFillStyle('#000000');

				// 加载背景图片
				uni.getImageInfo({
					src: this.shareImage,
					success: res => {
						console.log(`背景图缓存地址：${res.path}`);

						// 绘制背景图片（确保在最底层）
						ctx.drawImage(res.path, 0, 0, 390, 844);

						// 绘制名称
						ctx.setFontSize(16)
						this.writeTextOnCanvas(ctx, 30, 15, this.goodsTitle, 190, 520);

						// 绘制电话
						ctx.setFontSize(14)
						this.writeTextOnCanvas(ctx, 30, 15, this.phone, 190, 540);

						// 加载并绘制二维码
						uni.getImageInfo({
							src: this.qrCode,
							success: qrRes => {
								console.log(`二维码缓存地址：${qrRes.path}`);
								ctx.drawImage(qrRes.path, 95, 290, 200, 200);

								// 加载并绘制头像
								uni.getImageInfo({
									src: this.avater,
									success: avatarRes => {
										console.log(`头像缓存地址：${avatarRes.path}`);
										this.drawCircularImage(ctx, avatarRes.path,
											140, 518, 40);

										// 所有元素都绘制完成后再渲染
										ctx.draw(false, async () => {
											let pic = await this
												.getNewPic();
											uni.hideLoading();
											console.log(pic)
											this.$emit('success', pic);
										});
									},
									fail: err => {
										console.log(`头像加载失败：${err.errMsg}`);
										// 头像加载失败时仍继续渲染其他元素
										ctx.draw(false, async () => {
											let pic = await this
												.getNewPic();
											uni.hideLoading();
											this.$emit('success', pic);
										});
									}
								});
							},
							fail: err => {
								console.log(`二维码加载失败：${err.errMsg}`);
								// 二维码加载失败时仍继续渲染其他元素
								// 加载并绘制头像
								uni.getImageInfo({
									src: this.avater,
									success: avatarRes => {
										console.log(`头像缓存地址：${avatarRes.path}`);
										this.drawCircularImage(ctx, avatarRes.path,
											140, 518, 40);

										// 所有元素都绘制完成后再渲染
										ctx.draw(false, async () => {
											let pic = await this
												.getNewPic();
											uni.hideLoading();
											this.$emit('success', pic);
										});
									},
									fail: err => {
										console.log(`头像加载失败：${err.errMsg}`);
										// 头像加载失败时仍继续渲染其他元素
										ctx.draw(false, async () => {
											let pic = await this
												.getNewPic();
											uni.hideLoading();
											this.$emit('success', pic);
										});
									}
								});
							}
						});
					},
					fail: err => {
						console.log(`背景图缓存失败：${err.errMsg}`);
						// 背景图加载失败时，使用默认背景色并继续绘制其他元素
						ctx.setFillStyle('#f3f4f6')
						ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight)

						// 绘制名称
						ctx.setFontSize(16)
						this.writeTextOnCanvas(ctx, 30, 15, this.goodsTitle, 190, 520);

						// 绘制电话
						ctx.setFontSize(14)
						this.writeTextOnCanvas(ctx, 30, 15, this.phone, 190, 540);

						// 加载并绘制二维码
						uni.getImageInfo({
							src: this.qrCode,
							success: qrRes => {
								console.log(`二维码缓存地址：${qrRes.path}`);
								ctx.drawImage(qrRes.path, 95, 290, 200, 200);

								// 加载并绘制头像
								uni.getImageInfo({
									src: this.avater,
									success: avatarRes => {
										console.log(`头像缓存地址：${avatarRes.path}`);
										this.drawCircularImage(ctx, avatarRes.path,
											140, 518, 40);

										// 所有元素都绘制完成后再渲染
										ctx.draw(false, async () => {
											let pic = await this
												.getNewPic();
											uni.hideLoading();
											this.$emit('success', pic);
										});
									},
									fail: err => {
										console.log(`头像加载失败：${err.errMsg}`);
										// 头像加载失败时仍继续渲染其他元素
										ctx.draw(false, async () => {
											let pic = await this
												.getNewPic();
											uni.hideLoading();
											this.$emit('success', pic);
										});
									}
								});
							},
							fail: err => {
								console.log(`二维码加载失败：${err.errMsg}`);
								// 二维码加载失败时仍继续渲染其他元素
								// 加载并绘制头像
								uni.getImageInfo({
									src: this.avater,
									success: avatarRes => {
										console.log(`头像缓存地址：${avatarRes.path}`);
										this.drawCircularImage(ctx, avatarRes.path,
											140, 518, 40);

										// 所有元素都绘制完成后再渲染
										ctx.draw(false, async () => {
											let pic = await this
												.getNewPic();
											uni.hideLoading();
											this.$emit('success', pic);
										});
									},
									fail: err => {
										console.log(`头像加载失败：${err.errMsg}`);
										// 头像加载失败时仍继续渲染其他元素
										ctx.draw(false, async () => {
											let pic = await this
												.getNewPic();
											uni.hideLoading();
											this.$emit('success', pic);
										});
									}
								});
							}
						});
					}
				});
			},
			/**
			 * @param {Object} ctx_2d	getContext("2d") 对象
			 * @param {int} lineheight	段落文本行高
			 * @param {int} bytelength	设置单字节文字一行内的数量
			 * @param {string} text		写入画面的段落文本
			 * @param {int} startleft	开始绘制文本的 x 坐标位置（相对于画布）
			 * @param {int} starttop	开始绘制文本的 y 坐标位置（相对于画布）
			 */
			writeTextOnCanvas(ctx_2d, lineheight, bytelength, text, startleft, starttop) {
				// 获取字符串的真实长度（字节长度）
				function getTrueLength(str) {
					var len = str.length,
						truelen = 0;
					for (var x = 0; x < len; x++) {
						if (str.charCodeAt(x) > 128) {
							truelen += 2;
						} else {
							truelen += 1;
						}
					}
					return truelen;
				}
				// 按字节长度截取字符串，返回substr截取位置
				function cutString(str, leng) {
					var len = str.length,
						tlen = len,
						nlen = 0;
					for (var x = 0; x < len; x++) {
						if (str.charCodeAt(x) > 128) {
							if (nlen + 2 < leng) {
								nlen += 2;
							} else {
								tlen = x;
								break;
							}
						} else {
							if (nlen + 1 < leng) {
								nlen += 1;
							} else {
								tlen = x;
								break;
							}
						}
					}
					return tlen;
				}
				for (var i = 1; getTrueLength(text) > 0; i++) {
					var tl = cutString(text, bytelength);
					ctx_2d.fillText(text.substr(0, tl).replace(/^\s+|\s+$/, ""), startleft, (i - 1) * lineheight +
						starttop);
					text = text.substr(tl);
				}
			},
			
			
			// 获取新的图片地址
			getNewPic() {
				return new Promise((resolve, errs) => {
					uni.canvasToTempFilePath({
						canvasId: this.canvasID,
						quality: 1,
						complete: (res) => {
							// 在H5平台下，tempFilePath 为 base64
							resolve(res.tempFilePath)
						}
					}, this);
				})
			},
		}
	}
</script>